﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Mvc;
using System.Web.Routing;
using ActivateYourGlutes.Controllers;
using ActivateYourGlutes.Data;
using ActivateYourGlutes.Infrastructure;
using ActivateYourGlutes.Payloads.MeasurementTypePayloads;
using ActivateYourGlutes.Services;
using ActivateYourGlutes.Services.Model;
using NUnit.Framework;
using Rhino.Mocks;

namespace ActivateYourGlutes.Tests.Unit.Controllers
{
    [TestFixture]
    public class Test_MeasurementTypeController : ControllerTestBase
    {
        private MeasurementTypeController _measurementTypeController;
        private IMeasurementTypeProvider _measurementTypeProvider;
        private List<MeasurementTypeValueType> _valueTypes;

        [SetUp]
        public override void Init()
        {
            base.Init();
            _measurementTypeProvider = MockRepository.GenerateStub<IMeasurementTypeProvider>();
            _measurementTypeController = new MeasurementTypeController(_measurementTypeProvider, _commonAccountProvider, _logger);
            _valueTypes = new List<MeasurementTypeValueType>()
                              {
                                  new MeasurementTypeValueType() { Code = "P", Description = "Percentage"},
                                  new MeasurementTypeValueType() { Code = "L", Description = "Length"}
                              };
            _measurementTypeController.ControllerContext = new ControllerContext(_httpContext, new RouteData(), _measurementTypeController);
        }

        [Test]
        public void Test_Index_Get_ReturnsView()
        {
            // Arrange
            _measurementTypeProvider.Stub(mtp => mtp.MeasurementTypes(null)).Return(_measurementTypes).IgnoreArguments();

            // Act
            ViewResult result = (ViewResult) _measurementTypeController.Index();

            // Assert
            Assert.That(result.ViewData.Model, Is.EqualTo(_measurementTypes));
        }

        [Test]
        public void Test_Create_Get_ReturnsView()
        {
            // Arrange
            _measurementTypeProvider.Stub(mtp => mtp.ValueTypes()).Return(_valueTypes);

            // Act
            ViewResult result = (ViewResult) _measurementTypeController.Create();

            // Assert
            EditCreatePayload payload = (EditCreatePayload) result.ViewData.Model;
            Assert.That(payload.ValueTypes.Count(), Is.EqualTo(2));
            Assert.That(payload.ValueTypes.First().Value, Is.EqualTo("P"));
            Assert.That(payload.ValueTypes.Last().Value, Is.EqualTo("L"));
            Assert.That(payload.MeasurementType, Is.Not.Null);
        }

        [Test]
        public void Test_Create_Post_RedirectsToIndex()
        {
            // Arrange
            MeasurementType measurementType = new MeasurementType() {Description = "Test", Type = "Z"};
            _measurementTypeProvider.Expect(mtp => mtp.AddToAccount(null, null)).IgnoreArguments();

            // Act
            RedirectToRouteResult result = (RedirectToRouteResult) _measurementTypeController.Create(measurementType);

            // Assert
            Assert.That(result.RouteValues["action"], Is.EqualTo("Index"));
            Assert.That(result.RouteValues["controller"], Is.EqualTo("MeasurementType"));
            _measurementTypeProvider.VerifyAllExpectations();
        }

        [Test]
        public void Test_Create_Post_ValidationErrorReturnsView()
        {
            // Arrange
            MeasurementType measurementType = new MeasurementType() { Description = "Description", Type = "Z" };
            _measurementTypeProvider.Stub(mtp => mtp.ValueTypes()).Return(_valueTypes);
            _measurementTypeProvider.Stub(mtp => mtp.AddToAccount(null, null)).IgnoreArguments().Throw(
                new ValidationException("Description", "Error"));

            // Act
            ViewResult result = (ViewResult)_measurementTypeController.Create(measurementType);

            // Assert
            EditCreatePayload payload = (EditCreatePayload)result.ViewData.Model;
            Assert.That(result.ViewData.ModelState["Description"].Errors[0].ErrorMessage, Is.EqualTo("Error"));
            Assert.That(payload.MeasurementType, Is.EqualTo(measurementType));
        }

        [Test]
        public void Test_ConfirmDelete_ReturnsView()
        {
            // Arrange
            MeasurementType measurementType = new MeasurementType() { Description = "Description", Type = "Z" };
            _measurementTypeProvider.Stub(mtp => mtp.GetById(null, 1)).IgnoreArguments().Return(measurementType);

            // Act
            ViewResult result = (ViewResult) _measurementTypeController.ConfirmDelete(1);

            // Assert
            Assert.That(result.ViewData.Model, Is.EqualTo(measurementType));
        }

        [Test]
        public void Test_ConfirmDelete_UnauthorisedRedirects()
        {
            // Arrange
            _measurementTypeProvider.Stub(mtp => mtp.GetById(null, 1)).IgnoreArguments().Throw(
                new AuthorizationException("Unauthorized access"));

            // Act
            RedirectToRouteResult result = (RedirectToRouteResult) _measurementTypeController.ConfirmDelete(1);

            // Assert
            Assert.That(result.RouteValues["controller"], Is.EqualTo("Account"));
            Assert.That(result.RouteValues["action"], Is.EqualTo("Unauthorized"));
        }

        [Test]
        public void Test_Delete_DeletesAndRedirectsToIndex()
        {
            // Arrange
            _measurementTypeProvider.Expect(mtp => mtp.Delete(null, 1)).IgnoreArguments();

            // Act
            RedirectToRouteResult result = (RedirectToRouteResult) _measurementTypeController.Delete(1, "Yes");

            // Assert
            Assert.That(result.RouteValues["controller"], Is.EqualTo("MeasurementType"));
            Assert.That(result.RouteValues["action"], Is.EqualTo("Index"));
            _measurementTypeProvider.VerifyAllExpectations();
        }

        [Test]
        public void Test_Delete_NoDeleteAndRedirectsToIndex()
        {
            // Arrange
            _measurementTypeProvider.AssertWasNotCalled(mtp => mtp.Delete(Arg<Account>.Is.Anything, Arg<int>.Is.Anything));

            // Act
            RedirectToRouteResult result = (RedirectToRouteResult)_measurementTypeController.Delete(1, "No");

            // Assert
            Assert.That(result.RouteValues["controller"], Is.EqualTo("MeasurementType"));
            Assert.That(result.RouteValues["action"], Is.EqualTo("Index"));
            _measurementTypeProvider.VerifyAllExpectations();
        }

        [Test]
        public void Test_Delete_UnauthorizeRedirects()
        {
            // Arrange
            _measurementTypeProvider.Stub(mtp => mtp.Delete(Arg<Account>.Is.Anything, Arg<int>.Is.Anything)).Throw(
                new AuthorizationException("Unauthorized"));

            // Act
            RedirectToRouteResult result = (RedirectToRouteResult)_measurementTypeController.Delete(1, "Yes");

            // Assert
            Assert.That(result.RouteValues["controller"], Is.EqualTo("Account"));
            Assert.That(result.RouteValues["action"], Is.EqualTo("Unauthorized"));
        }
    }
}
